"""
holt-winter季节性阻尼方法
test: mae; 1760.7532958984375， mape: 4.894587993621826, rmse: 1995.978759765625
"""
import os
import numpy as np
import pandas as pd
from statsmodels.tsa.api import ExponentialSmoothing
import matplotlib.pyplot as plt
from pylab import mpl
from keras.metrics import (RootMeanSquaredError,
                           MeanAbsoluteError,
                           MeanAbsolutePercentageError)
from model_evalute import Evalute, check_noise


# 指定默认字体
mpl.rcParams['font.sans-serif'] = ['SimHei']
# 解决保存图像是负号'-'显示为方块的问题
mpl.rcParams['axes.unicode_minus'] = False


def holt_winter_damped(data, pic_save_path):
    """
    holt-winter季节性阻尼方法
    :param data:
    :param pic_save_path: 图片存储路径
    :return:
    """
    series_train = data.loc[: '2019-08']
    series_test = data.loc['2019-09':]

    #  建模
    model = ExponentialSmoothing(endog=series_train.to_numpy(),
                                 damped=True,
                                 seasonal_periods=12,
                                 trend='additive',
                                 seasonal='multiplicative').fit()
    print(model.summary())
    #  预测
    train_pred = model.predict(start=0, end=len(series_train)-1)
    train_pred_series = pd.Series(train_pred, index=series_train.index)

    pred = model.forecast(steps=len(series_test))
    pred_series = pd.Series(pred, index=series_test.index)

    #  模型概况
    data.plot()
    train_pred_series.plot()
    pred_series.plot()

    plt.legend(['观测值', '拟合', '预测值'])
    plt.xlabel('日期')
    plt.ylabel('货运量')
    plt.title('holt-winter模型')
    pic_name = r'Holt-Winters阻尼季节性模型.png'
    # plt.savefig(os.path.join(pic_save_path, pic_name))
    plt.show()

    #  训练评估
    evalute = Evalute(y_true=series_train, y_pred=train_pred_series)
    mae, mse, aic, aicc, bic = evalute.evalute_error_index()
    print('\n训练结果的参数评估：\n残差评估：mae: {}; mse: {}\n'
          '信息准则评估：aic: {}; aicc: {}; bic: {}'.
          format(mae, mse, aic, aicc, bic))

    # 预测评估
    # mae
    mae = MeanAbsoluteError()
    mae.update_state(y_true=series_test, y_pred=pred)
    test_mae = mae.result()

    # mape
    mape = MeanAbsolutePercentageError()
    mape.update_state(y_true=series_test, y_pred=pred)
    test_mape = mape.result()

    # rmse
    rmse = RootMeanSquaredError()
    rmse.update_state(y_true=series_test, y_pred=pred)
    test_rmse = rmse.result()

    print('test: mae; {}， mape: {}, rmse: {}'.
          format(test_mae, test_mape, test_rmse))

    train_err = series_train - train_pred_series
    # 白噪音检验
    check_noise(err=train_err)

    low = []
    high = []
    err_std = np.std(train_err, ddof=1)
    # 99% 2.576
    # 95% 1.96
    # 90% 1.645
    for num in pred_series:
        low.append(num - 1.96 * err_std)
        high.append(num + 1.96 * err_std)

    print('err_std: {}'.format(err_std))
    evalute = Evalute(y_true=series_test, y_pred=pred_series,
                      low=low, high=high)
    mae, mse, aic, aicc, bic = evalute.evalute_error_index()
    accuracy_score = evalute.accuracy()
    print('\n测试结果的参数评估：\n残差评估：mae: {}; mse: {}\n准确率：{}'.
          format(mae, mse, accuracy_score))
